/* $Id: VBoxMPGaExt.h $ */
/** @file
 * VirtualBox Windows Guest Mesa3D - Gallium driver miscellaneous helpers and common includes.
 */

/*
 * Copyright (C) 2017-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef _WDDM_INCLUDE_GALLIUM_VBOXMPGAEXT_H_
#define _WDDM_INCLUDE_GALLIUM_VBOXMPGAEXT_H_

#include "list.h"
#include "gallium/Svga.h"

#define VBOXWDDM_GA_MAX_FENCE_OBJECTS 4096

/* Gallium related device extension. */
typedef struct VBOXWDDM_EXT_GA
{
    union
    {
        /* Pointers to HW specific structs. */
        PVBOXWDDM_EXT_VMSVGA pSvga;
        void *pv;
    } hw;

    volatile UINT32 u32LastSubmittedFenceId; /* Updated in GaDxgkSubmitCommand. */
    volatile UINT32 u32LastCompletedFenceId; /* Updated in ISR. */
    volatile UINT32 u32PreemptionFenceId; /* Updated in GaDxgkDdiPreemptCommand. */
    volatile UINT32 u32LastCompletedSeqNo; /* Updated in DPC routine. */

    volatile UINT32 u32UseSoftCursor;
    void* pvImageTransCursor;

    RTLISTANCHOR listHwRenderData;

    struct
    {
        /* Generation of SeqNo's. */
        volatile UINT32 u32SeqNoSource;
        /* Lock for accessing fence objects. Spin lock because it is used in DPC routine too. */
        KIRQL OldIrql;
        KSPIN_LOCK SpinLock;
        /* List of all fence objects. */
        RTLISTANCHOR list;
        /** Bitmap of used fence handles. Bit 0 - fence handle 0, etc. */
        UINT32 au32HandleBits[(VBOXWDDM_GA_MAX_FENCE_OBJECTS + 31) / 32];
    } fenceObjects;
} VBOXWDDM_EXT_GA, *PVBOXWDDM_EXT_GA;

/* Fence object (FO). */
typedef struct GAFENCEOBJECT
{
    volatile UINT32 cRefs;    /* By UM driver, by waiter, during submission. */
    UINT32 u32FenceHandle;    /* Unique identifier, used for communications with UM driver. */
    UINT32 u32FenceState;     /* GAFENCE_STATE_* */
    UINT32 fu32FenceFlags;    /* GAFENCE_F_* */
    UINT32 u32SubmissionFenceId; /* DXGK fence id. */
    UINT32 u32SeqNo;            /* Gallium Sequence Number, generated by the miniport. */
    PVBOXWDDM_DEVICE pDevice;   /* Device the fence is associated with. */
    KEVENT event;               /* Allows to wait for the fence completion. */
    RTLISTNODE node;            /* For the per adapter list of fence objects. */
    UINT32 u64SubmittedTS;    /* Nanoseconds timestamp when the corresponding buffer was submitted. */
} GAFENCEOBJECT;

/*
 * Description of DMA buffer content.
 * These structures are stored in DmaBufferPrivateData.
 */
typedef struct GARENDERDATA
{
    UINT32          u32DataType;    /* GARENDERDATA_TYPE_* */
    UINT32          cbData;         /* How many bytes. */
    GAFENCEOBJECT   *pFenceObject;  /* User mode fence associated with this command buffer. */
    void            *pvDmaBuffer;   /* Pointer to the DMA buffer. */
    GAHWRENDERDATA  *pHwRenderData; /* The hardware module private data. */
} GARENDERDATA;

#define GAFENCE_STATE_IDLE      0
#define GAFENCE_STATE_SUBMITTED 1
#define GAFENCE_STATE_SIGNALED  2

#define GAFENCE_F_WAITED        0x1 /* KEVENT is initialized and there is(are) waiter(s). */
#define GAFENCE_F_DELETED       0x2 /* The user mode driver deleted this fence. */

#define GARENDERDATA_TYPE_RENDER   1
#define GARENDERDATA_TYPE_PRESENT  2
#define GARENDERDATA_TYPE_PAGING   3
#define GARENDERDATA_TYPE_FENCE    4

NTSTATUS GaFenceCreate(PVBOXWDDM_EXT_GA pGaDevExt,
                       PVBOXWDDM_DEVICE pDevice,
                       UINT32 *pu32FenceHandle);
NTSTATUS GaFenceQuery(PVBOXWDDM_EXT_GA pGaDevExt,
                      UINT32 u32FenceHandle,
                      UINT32 *pu32SubmittedSeqNo,
                      UINT32 *pu32ProcessedSeqNo,
                      UINT32 *pu32FenceStatus);
NTSTATUS GaFenceWait(PVBOXWDDM_EXT_GA pGaDevExt,
                     UINT32 u32FenceHandle,
                     UINT64 u64TimeoutNS);
NTSTATUS GaFenceDelete(PVBOXWDDM_EXT_GA pGaDevExt,
                       UINT32 u32FenceHandle);

DECLINLINE(void) gaFenceObjectsLock(VBOXWDDM_EXT_GA *pGaDevExt)
{
    KeAcquireSpinLock(&pGaDevExt->fenceObjects.SpinLock, &pGaDevExt->fenceObjects.OldIrql);
}

DECLINLINE(void) gaFenceObjectsUnlock(VBOXWDDM_EXT_GA *pGaDevExt)
{
    KeReleaseSpinLock(&pGaDevExt->fenceObjects.SpinLock, pGaDevExt->fenceObjects.OldIrql);
}

void GaFenceObjectsDestroy(VBOXWDDM_EXT_GA *pGaDevExt,
                           PVBOXWDDM_DEVICE pDevice);
GAFENCEOBJECT *GaFenceLookup(VBOXWDDM_EXT_GA *pGaDevExt,
                             UINT32 u32FenceHandle);
void GaFenceUnrefLocked(VBOXWDDM_EXT_GA *pGaDevExt,
                        GAFENCEOBJECT *pFO);

NTSTATUS GaFenceObjectPoolInit();
void GaFenceObjectPoolDestroy(VBOXWDDM_EXT_GA *pGaDevExt);

void vboxWddmSendTransparentHostCursor(PVBOXMP_DEVEXT pDevExt);
bool vboxWddmUpdatePointerShape(PVBOXMP_DEVEXT pDevExt, PVIDEO_POINTER_ATTRIBUTES pAttrs, UINT32 cbLength);

#endif
